/* eslint-disable no-unused-vars */
/* eslint-disable init-declarations */
/*
 * @Author: shawnxiao
 * @Date: 2021-04-11 18:21:26
 * @LastEditTime: 2021-11-12 18:21:41
 * @FilePath: /gatt-react/src/common/utils/index.ts
 */
import { useEffect, useState } from 'react'
import config from '../config'

// 节流
export const useDebounce = <V>(value: V, delay: number = 50) => {
  const [deBouncedValue, setDeBouncedValue] = useState(value)

  useEffect(() => {
    // 每次在value变化以后，设置一个定时器
    const timeout = setTimeout(() => setDeBouncedValue(value), delay)
    // 每次在上一个useEffect处理完以后再运行
    return () => clearTimeout(timeout)
  }, [value, delay])

  return deBouncedValue
}

/**
 * @desc 函数防抖 触发高频事件 N 秒后只会执行一次，如果 N 秒内事件再次触发，则会重新计时。
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param immediate true 表立即执行，false 表非立即执行
 * var setUseAction = debounce(getUserAction, 10000, true);
 * node.onmousemove = setUseAction // 使用防抖
 * setUseAction.cancel() // 取消防抖
 */
export function debounce(func: Function, wait = 50, immediate?: Boolean) {
  let timeout: any, result: any
  const debounced = function (this: any) {
    const context = this
    // eslint-disable-next-line prefer-rest-params
    const args = arguments

    if (timeout) clearTimeout(timeout)
    if (immediate) {
      // 如果已经执行过，不再执行
      const callNow = !timeout
      timeout = setTimeout(() => {
        timeout = null
      }, wait)
      if (callNow) result = func.apply(context, args)
    } else {
      timeout = setTimeout(() => {
        func.apply(context, args)
      }, wait)
    }
    return result
  }
  debounced.cancel = function () {
    clearTimeout(timeout)
    timeout = null
  }

  return debounced
}

/**
 * @desc 函数节流 触发高频事件，且 N 秒内只执行一次。
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param options.leading 来表示是否可以立即执行一次，opitons.trailing 表示结束调用的时候是否还要执行一次，默认都是 true。 注意设置的时候不能同时将 leading 或 trailing 设置为 false。
 */
export function throttle(func: Function, wait: number = 50, options?: any) {
  let timeout: any, context: any, args: any
  let previous = 0
  if (!options) options = {}
  const later = function () {
    previous = options.leading === false ? 0 : new Date().getTime()
    timeout = null
    func.apply(context, args)
    if (!timeout) context = args = null
  }

  const throttled: any = function (this: any) {
    const now = new Date().getTime()
    if (!previous && options.leading === false) previous = now
    const remaining = wait - (now - previous)
    context = this
    // eslint-disable-next-line prefer-rest-params
    args = arguments
    if (remaining <= 0 || remaining > wait) {
      if (timeout) {
        clearTimeout(timeout)
        timeout = null
      }
      previous = now
      func.apply(context, args)
      if (!timeout) context = args = null
    } else if (!timeout && options.trailing !== false) {
      timeout = setTimeout(later, remaining)
    }
  }

  throttled.cancel = function () {
    clearTimeout(timeout)
    previous = 0
    timeout = null
  }
  return throttled
}

// 获取页面的名称作为token key
export function getTokenKeyForPage() {
  const pathname = window.location.pathname
  let htmlName = pathname.substring(1, pathname.indexOf('.'))
  // 首字母大写
  htmlName = htmlName.charAt(0).toUpperCase() + htmlName.slice(1)
  // 取页面名来区分不同的token
  const tokenKeyPage = config.TOKEN_KEY + (htmlName ? `-${htmlName}` : '-Index')
  return tokenKeyPage
}

// 获取iframe父级URL
export function getParentUrl() {
  let url = null
  if (parent !== window) {
    try {
      url = parent.location.host
    } catch (e) {
      url = document.referrer
    }
  }
  return url
}

export function dataURLtoFile(dataUrl: any, filename = 'file') {
  if (typeof dataUrl === 'object') {
    return new File([dataUrl], `${filename}.jpg`, { type: 'jpg' })
  }
  const arr = dataUrl.split(',')
  const mime = arr[0].match(/:(.*?);/)[1]
  const suffix = mime.split('/')[1]
  const bstr = atob(arr[1])
  let n = bstr.length
  const u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new File([u8arr], `${filename}.${suffix}`, { type: mime })
}

export const getRandomStr = () => {
  return new Date().getTime() + Math.random().toString(16).slice(2)
}

export function isFunction(fun: any) {
  return Object.prototype.toString.call(fun) === '[object Function]'
}
export function isObject(fun: any) {
  return Object.prototype.toString.call(fun) === '[object Object]'
}

export function jsonp({ url, data }: any): any {
  if (!url) {
    throw new Error('url is necessary')
  }
  try {
    return new Promise((resolve) => {
      const callback = 'CALLBACK' + Math.random().toString().substr(9, 18)
      const JSONP = document.createElement('script')
      JSONP.setAttribute('type', 'text/javascript')
      const headEle = document.getElementsByTagName('head')[0]
      let ret = ''
      if (data) {
        if (typeof data === 'string') {
          ret = '&' + data
        } else if (typeof data === 'object') {
          // eslint-disable-next-line guard-for-in
          for (const key in data) ret += '&' + key + '=' + encodeURIComponent(data[key])
        }
      }
      ret += '&_time=' + Date.now()
      JSONP.src = `${url}?callback=${callback}${ret}`
      window[callback] = (result: any) => {
        resolve(result)
        headEle.removeChild(JSONP)
        delete window[callback]
      }
      headEle.appendChild(JSONP)
    })
  } catch (err) {
    console.log(err)
  }
}

// 获取链接参数
export function getQueryString(name: string, url?: string) {
  const href = url || window.location.href
  if (href.includes('?') && href.includes(name)) {
    const arr: any[] = href
      .split('?')
      .filter((x) => x.includes(name))
      .join()
      .split('&')
    return arr
      .find((item) => {
        return item.includes(name)
      })
      .split('=')[1]
  }
  return null
}

/**
 * 获取URL参数并以对象数据形式返回
 * @param {string} url
 * @returns {Object}
 */
export function getQueryObject(url: string) {
  url = url ? url : window.location.href
  const search = url.substring(url.lastIndexOf('?') + 1)
  const obj: any = {}
  const reg = /([^?&=]+)=([^?&=]*)/g
  search.replace(reg, (rs, $1, $2) => {
    const name = decodeURIComponent($1)
    let val = decodeURIComponent($2)
    val = String(val)
    obj[name] = val
    return rs
  })
  return obj
}
// 生成uuid
export function uuid(len?: number, radix?: number) {
  const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
  // eslint-disable-next-line prefer-const
  let uuid = [],
    i
  radix = radix || chars.length

  if (len) {
    for (i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)]
  } else {
    let r
    uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
    uuid[14] = '4'

    for (i = 0; i < 36; i++) {
      if (!uuid[i]) {
        r = 0 | (Math.random() * 16)
        uuid[i] = chars[i === 19 ? (r & 0x3) | 0x8 : r]
      }
    }
  }
  return uuid.join('')
}
// 将rgba字符串对象转化为rgba对象
export function rgba2Obj(rgba = '') {
  const reg = /rgba\((\d+),(\d+),(\d+),(\d+)\)/g
  let rgbaObj: any = { r: 0, g: 0, b: 0, a: 0 }

  rgba.replace(reg, (_m, r, g, b, a) => {
    rgbaObj = { r, g, b, a }
    return rgba
  })
  return rgbaObj
}

export function formatTime(fmt: string, dateObj?: any) {
  const date = dateObj || new Date()
  const o: any = {
    'M+': date.getMonth() + 1, // 月份
    'd+': date.getDate(), // 日
    'h+': date.getHours(), // 小时
    'm+': date.getMinutes(), // 分
    's+': date.getSeconds(), // 秒
    'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
    S: date.getMilliseconds() // 毫秒
  }
  if (/(y+)/.test(fmt)) {
    fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
  }
  for (const k in o) {
    if (new RegExp('(' + k + ')').test(fmt)) {
      fmt = fmt.replace(
        RegExp.$1,
        RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
      )
    }
  }
  return fmt
}

// 金额千分位
export const currency = (v: any) => {
  const [n, d = []] = v.toString().split('.')
  return [n.replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')].concat(d).join('.')
}

// 时间戳格式化
export const timestampToTime = (timestamp: any, type?: any) => {
  const date = new Date(timestamp) // 时间戳为10位需*1000，时间戳为13位的话不需乘1000
  const Y = date.getFullYear() + '-'
  const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-'
  const D = date.getDate() < 10 ? '0' + date.getDate() + ' ' : date.getDate() + ''
  const h = date.getHours() < 10 ? '0' + date.getHours() + ':' : date.getHours() + ':'
  const m = date.getMinutes() < 10 ? '0' + date.getMinutes() + ':' : date.getMinutes() + ':'
  const s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
  if (type === 'second') {
    return Y + M + D + ' ' + h + m + s
  }
  return Y + M + D
}

/**
 * 对象数组去重,type表示对象里面的一个属性
 */
export const uniqueFun = (arr: any[], type: any) => {
  const res = new Map()
  return arr.filter((a) => !res.has(a[type]) && res.set(a[type], 1))
}

// 判断是否为闰年
/**
 * @param  {Number} year 传入年份
 */
export const isLeapYear = (year: number) => {
  return year % 4 > 0
}

// 树形转扁平
// 把 level, Id, Name, Pid 这些想要获取的键值名作为参数带进去,给每个层级增加一个level
// flatten(arr, ['Id', 'Name', 'Pid', 'id'])
export function flatten(data: any[], keys: any[], level: number = 0): any {
  return data.reduce(
    (arr, x) => [
      ...arr,
      keys.reduce(
        (o, k) => {
          o[k] = x[k] === 0 ? x[k] : x[k] ? x[k] : ''
          return o
        },
        { level }
      ),
      ...flatten(x.children || [], keys, level + 1)
    ],
    []
  )
}
/**
 * @description 将扁平化数据 转换成 树状结构
 * @param {Array} list 扁平化的数据
 * @param {String} parentField parentId的key名
 * @param {String} keyField id的key名
 * @param {String} childField children的key名
 */
export function formatToTree(list: any[], options: any = {}) {
  const { keyField = 'id', childField = 'children', parentField = 'parentId' } = options

  const tree = [] // 用来储存最终树形结构数据的数组
  const record = {} // 用来储存{key: obj}格式的对象

  // 将数据变换成{key: obj}格式，方便下面处理数据
  for (let i = 0; i < list.length; i++) {
    record[list[i][keyField]] = list[i]
  }
  // 根据parentField来将数据进行格式化
  for (let j = 0; j < list.length; j++) {
    // 判断父级是否存在
    const haveParent = record[list[j][parentField]]
    if (haveParent) {
      // 如果有没有父级children字段，就创建一个children字段
      !haveParent[childField] && (haveParent[childField] = [])
      // 在父级里插入子项
      haveParent[childField].push(list[j])
    } else {
      // 如果没有父级直接插入到最外层
      tree.push(list[j])
    }
  }
  return tree
}
/**
 * @description 将扁平化数据 转换成 树状结构
 * @param {Array} list 扁平化的数据
 * @param {String} parentField parentId的key名
 * @param {String} keyField id的key名
 * @param {String} childField children的key名
 */
export function transformTree(list: any[], options: any = {}) {
  const { keyField = 'id', childField = 'children', parentField = 'parentId' } = options

  const tree = []
  const record = {}

  for (let i = 0, len = list.length; i < len; i++) {
    const item = list[i]
    const id = item[keyField]

    if (!id) {
      continue
    }

    if (record[id]) {
      item[childField] = record[id]
    } else {
      item[childField] = record[id] = []
    }

    if (item[parentField]) {
      const parentId = item[parentField]

      if (!record[parentId]) {
        record[parentId] = []
      }

      record[parentId].push(item)
    } else {
      tree.push(item)
    }
  }

  return tree
}
